/**
@file
	ConnectionImpl.cpp
@brief

@author
	GengYong
@revision
	2005/11/05 * Created by GengYong.
*/


#include "StdUtility.h"
#include "ConnectionImpl.h"
#include "KernelLoader.h"

#include <cassert>

using namespace SAF;

ConnectionImpl::StoreTree::StoreTree(const char * name, unsigned long size)
{
	PERFCOUNTER("ConnectionImpl::StoreTree::StoreTree");

	this->name = Util::Util_AllocString(name);
	this->data = new char[size];
	this->size = size;
	this->lleaf = 0;
	this->rleaf = 0;
	return;
}

ConnectionImpl::StoreTree::~StoreTree()
{
	if (this->name != 0) Util::Util_FreeString(this->name);
	if (this->data != 0) delete[] (char*)(this->data);
	if (this->lleaf != 0) delete this->lleaf;
	if (this->rleaf != 0) delete this->rleaf;
	return;
}

ConnectionImpl::ConnectionImpl(IMessageRouter * router, unsigned long nodeid, unsigned long stateid, void * cookie)
:IConnection(router, nodeid), m_storeRoot(0), m_stateIndex(0)
{
	PERFCOUNTER("ConnectionImpl::ConnectionImpl");

	IKernel * const kernel = KernelLoader::Instance().Kernel();
	if (kernel != NULL)
	{		
		for (unsigned int i = 0; i < sizeof(m_stateStack)/sizeof(m_stateStack[0]); i++)
		{
			m_stateStack[i].stateId = (unsigned long)(-1);
			m_stateStack[i].cookie	= 0;
		}

		m_stateIndex++;
		m_stateStack[m_stateIndex].stateId	= stateid;
		m_stateStack[m_stateIndex].cookie	= cookie;
		
		IServiceModule ** serviceModuleList = 0;
		unsigned long serviceModuleCount = kernel->GetServiceModuleDiffList(stateid, (unsigned long)(-1), serviceModuleList);
		for (unsigned int index = 0; index < serviceModuleCount; index++)
		{
			serviceModuleList[index]->OnConnectionIncoming(this, cookie);
		}
	}
	
	this->m_stateBits = (StateBits(0x1) << stateid);
	
	return;
}

ConnectionImpl::~ConnectionImpl()
{
	if (m_stateIndex > 0)
	{
		IKernel * const kernel = KernelLoader::Instance().Kernel();
		if (kernel != NULL)
		{
			while (m_stateIndex > 0)
			{
				IServiceModule ** dropServiceModuleList = 0;			
				unsigned long dropServiceModuleCount = kernel->GetServiceModuleDiffList
					(m_stateStack[m_stateIndex].stateId, m_stateStack[m_stateIndex - 1].stateId, dropServiceModuleList);		
				for (unsigned long index = 0; index < dropServiceModuleCount; index++)
				{
					dropServiceModuleList[index]->OnConnectionOutgoing(this, m_stateStack[m_stateIndex].cookie);
				}
				m_stateIndex--;
			}
		}
	}

	if (this->m_storeRoot != NULL)
	{
		delete this->m_storeRoot;
		this->m_storeRoot = 0;
	}
	return;
}

bool ConnectionImpl::EnterState(const char * statename, void * cookie)
{
	PERFCOUNTER("ConnectionImpl::EnterState");

	IKernel * const kernel = KernelLoader::Instance().Kernel();
	if (kernel != NULL)
	{
		int currStateId = kernel->GetStateFromName(statename);
		
		assert(currStateId > 0 && "the state name not exist.");

		if (currStateId > 0)
		{
			for (int index = 0; index < this->m_stateIndex; index++)
			{
				if (this->m_stateStack[index].stateId == currStateId)
				{
					assert(!"this state has joined. ");
					while (LeaveState() != currStateId){;}
					return true;
				}
			}
			
			int prevStateId = m_stateStack[m_stateIndex].stateId;

			IServiceModule ** dropServiceModuleList = 0;
			IServiceModule ** joinServiceModuleList = 0;
			int dropServiceModuleCount = kernel->GetServiceModuleDiffList(prevStateId, currStateId, dropServiceModuleList);
			int joinServiceModuleCount = kernel->GetServiceModuleDiffList(currStateId, prevStateId, joinServiceModuleList);
//@!!!!!!!!!!!!					
			for (int index = 0; index < dropServiceModuleCount; index++)
			{
				//dropServiceModuleList[index]->OnConnectionNodeBO(this, cookie);
			}			

			for (int index = 0; index < joinServiceModuleCount; index++)
			{
				//joinServiceModuleList[index]->OnConnectionNodeFI(this, cookie);
			}
//@!!!!!!!!!!!!!!!!!
			m_stateIndex++;
			m_stateStack[m_stateIndex].stateId  = currStateId;
			m_stateStack[m_stateIndex].cookie	= cookie;
			
			this->m_stateBits = (StateBits(0x1) << currStateId);
			return true;
		}
	}
	return false;
}

int ConnectionImpl::LeaveState()
{
	PERFCOUNTER("ConnectionImpl::LeaveState");

	if (this->m_stateIndex != 0)
	{
		IKernel * const kernel = KernelLoader::Instance().Kernel();
		if (kernel != NULL)
		{
			IServiceModule ** dropServiceModuleList = 0;
			IServiceModule ** joinServiceModuleList = 0;
			unsigned long dropServiceModuleCount = kernel->GetServiceModuleDiffList
				(m_stateStack[m_stateIndex].stateId, m_stateStack[m_stateIndex - 1].stateId, dropServiceModuleList);
			unsigned long joinServiceModuleCount = kernel->GetServiceModuleDiffList
				(m_stateStack[m_stateIndex - 1].stateId, m_stateStack[m_stateIndex].stateId, joinServiceModuleList);
//@--------------
			for (unsigned long index = 0; index < dropServiceModuleCount; index++)
			{
				//dropServiceModuleList[index]->OnConnectionNodeFO(this, m_stateStack[m_stateIndex].cookie);
			}

			for (unsigned long index = 0; index < joinServiceModuleCount; index++)
			{
				//joinServiceModuleList[index]->OnConnectionNodeBI(this, m_stateStack[m_stateIndex].cookie);
			}
//@--------------
			m_stateIndex--;	
		}

		this->m_stateBits = (StateBits(0x1) << m_stateStack[m_stateIndex].stateId);
	}
	return this->m_stateStack[m_stateIndex].stateId;
}

void * ConnectionImpl::Store(const char * name, const void * val, unsigned long size) const
{
	assert(name != 0);
	assert(val != 0);
	assert(size != 0);

	PERFCOUNTER("ConnectionImpl::Store");

	ConnectionImpl::StoreTree **  pnode = &(this->m_storeRoot);	

	Util::CompareResult result = Util::equal;
	while (((*pnode) != 0) && (Util::equal != (result = Util::Util_CompareString((*pnode)->name, name))))
	{	
		pnode = (result == Util::less ? &((*pnode)->rleaf) : &((*pnode)->lleaf));		
	}

	if (0 != (*pnode))  
	{
		if (size == (*pnode)->size)
		{	
			Util::Util_MemoryCopy((*pnode)->data, val, size);
			return (*pnode)->data;
		}

		char * buf = new char[size];
		if (buf != 0)
		{
			delete[] (char*)((*pnode)->data);
			(*pnode)->data = buf;
			(*pnode)->size = size;
			Util::Util_MemoryCopy((*pnode)->data, val, size);
			return (*pnode)->data;			
		}
	}
	else if (0 != ((*pnode) = new ConnectionImpl::StoreTree(name, size)))
	{
		Util::Util_MemoryCopy((*pnode)->data, val, size);
		return (*pnode)->data;
	}
	
	return 0;
}

void * ConnectionImpl::Restore(const char * name, unsigned long * psize) const
{
	PERFCOUNTER("ConnectionImpl::Restore");

	ConnectionImpl::StoreTree * node = this->m_storeRoot;	

	Util::CompareResult result = Util::equal;
	while ((node != 0) && (Util::equal != (result = Util::Util_CompareString(node->name, name))))
	{	
		node = (result == Util::less ? (node->rleaf) : (node->lleaf));		
	}

	if (0 != node)  
	{
		if (psize != 0)	*psize = node->size;		
		return node->data;	
	}

	if (psize != 0) *psize = 0;
	return 0;
}


